package com.stud.system.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.stud.common.constant.WorkflowConstants;
import com.stud.common.core.domain.WorkflowEntity;
import com.stud.common.core.domain.model.LoginUser;
import com.stud.common.enums.FileBusinessType;
import com.stud.common.enums.RoleEnum;
import com.stud.common.enums.WorkflowDefinitionEnum;
import com.stud.common.enums.WorkflowStatusEnum;
import com.stud.common.exception.ServiceException;
import com.stud.common.jdbc.MyJdbcTemplate;
import com.stud.common.utils.SecurityUtils;
import com.stud.system.domain.*;
import com.stud.system.dto.WorkflowAuthDTO;
import com.stud.system.request.workflow.WorkflowApproveRequest;
import com.stud.system.request.workflow.WorkflowAuthRequest;
import com.stud.system.request.workflow.WorkflowRejectRequest;
import com.stud.system.service.*;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.stud.common.mybatis.BaseServiceImpl;
import com.stud.system.mapper.WorkflowMapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * 流程实例Service业务层处理
 *
 * @author Stud
 * @date 2023-03-06
 */
@Service
@RequiredArgsConstructor
public class WorkflowServiceImpl extends BaseServiceImpl<WorkflowMapper, Workflow> implements WorkflowService {

    private final WorkflowDefinitionService workflowDefinitionService;

    private final WorkflowDefinitionTaskService workflowDefinitionTaskService;

    private final WorkflowTaskService workflowTaskService;

    private final WorkflowLogService workflowLogService;

    private final SysRoleServiceImpl roleService;

    private final FileLinkService fileLinkService;

    private final MyJdbcTemplate jdbcTemplate;

    @Override
    public WorkflowAuthDTO workflowAuth(WorkflowAuthRequest request) {
        //没启动的只有启动权限
        if (Objects.isNull(request.getWorkflowId())) {
            WorkflowAuthDTO workflowAuthDTO = new WorkflowAuthDTO();
            workflowAuthDTO.setStart(true);
            return workflowAuthDTO;
        }

        Workflow workflow = this.getById(request.getWorkflowId());
        //数据异常的作废
        if (Objects.isNull(workflow)) {
            throw new ServiceException("查询流程实例失败");
        }

        if (Objects.equals(workflow.getDefinitionType(), WorkflowConstants.DEFINITION_TYPE_1)) {
            return parallelWorkflowAuth(workflow, request.getTaskId());
        }

        WorkflowAuthDTO workflowAuthDTO = new WorkflowAuthDTO();

        //已驳回的可以也只能重新启动
        if (Objects.equals(workflow.getWorkflowStatus(), WorkflowStatusEnum.FAIL.getCode())) {
            workflowAuthDTO.setStart(true);
            return workflowAuthDTO;
        }

        //没有当前节点,说明流程已经彻底完成了(主任务审批通过,普通任务全部审批通过)
        if (Objects.isNull(workflow.getTaskId())) {
            return workflowAuthDTO;
        }

        //找不到当前任务的作废
        WorkflowTask workflowTask = this.workflowTaskService.getById(workflow.getTaskId());
        if (Objects.isNull(workflowTask)) {
            throw new ServiceException("查询流程实例任务失败");
        }

        //只有流程管理员和当前节点设置的角色才可以审批
        if (roleService.checkRole(SecurityUtils.getUserId(), RoleEnum.WORKFLOW.getRoleKey(), workflowTask.getRoleCode())) {
            workflowAuthDTO.setTaskInfo(true);
            workflowAuthDTO.setApprove(true);
            workflowAuthDTO.setReject(true);
            if (!Objects.equals(workflowTask.getFileFlag(), WorkflowConstants.TASK_FILE_FLAG_0)) {
                workflowAuthDTO.setAttachment(true);
            }
        }
        return workflowAuthDTO;
    }

    private WorkflowAuthDTO parallelWorkflowAuth(Workflow workflow, Long taskId) {
        WorkflowAuthDTO workflowAuthDTO = new WorkflowAuthDTO();
        //已驳回的可以也只能重新启动
        if (Objects.equals(workflow.getWorkflowStatus(), WorkflowStatusEnum.FAIL.getCode())) {
            workflowAuthDTO.setStart(true);
            return workflowAuthDTO;
        }

        Set<String> roleSet = this.roleService.selectRoleKeysByUserId(SecurityUtils.getUserId());
        if (Objects.isNull(taskId)) {
            List<WorkflowTask> workflowTaskList = this.workflowTaskService.listByWorkflowId(workflow.getId());
            if (CollectionUtils.isEmpty(workflowTaskList)) {
                throw new ServiceException("查询流程任务实例失败");
            }

            List<Long> taskIdList = Lists.newArrayList();
            for (WorkflowTask workflowTask : workflowTaskList) {
                if (Objects.equals(workflowTask.getTaskStatus(), WorkflowConstants.TASK_STATUS_0) && roleService.checkRole(roleSet, SecurityUtils.getUserId(), RoleEnum.WORKFLOW.getRoleKey(), workflowTask.getRoleCode())) {
                    taskIdList.add(workflowTask.getId());
                }
            }
            //并行流程暂时不控制那么细
            if (!CollectionUtils.isEmpty(taskIdList)) {
                workflowAuthDTO.setTaskInfo(true);
                workflowAuthDTO.setApprove(true);
                workflowAuthDTO.setReject(true);
                workflowAuthDTO.setAttachment(true);
                workflowAuthDTO.setTaskIds(taskIdList.toArray(new Long[0]));
            }
            return workflowAuthDTO;
        }

        //如果已经选择要审批的任务
        WorkflowTask workflowTask = this.workflowTaskService.getById(taskId);
        if (Objects.isNull(workflowTask)) {
            throw new ServiceException("查询流程实例任务失败");
        }

        //只有流程管理员和当前节点设置的角色才可以审批
        if (roleService.checkRole(roleSet, SecurityUtils.getUserId(), RoleEnum.WORKFLOW.getRoleKey(), workflowTask.getRoleCode())) {
            workflowAuthDTO.setTaskInfo(true);
            workflowAuthDTO.setApprove(true);
            workflowAuthDTO.setReject(true);
            if (!Objects.equals(workflowTask.getFileFlag(), WorkflowConstants.TASK_FILE_FLAG_0)) {
                workflowAuthDTO.setAttachment(true);
            }
        }
        return workflowAuthDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long start(Long businessId, WorkflowDefinitionEnum workflowDefinitionEnum) {
        WorkflowDefinition workflowDefinition = this.workflowDefinitionService.getByDefinitionEnum(workflowDefinitionEnum);
        if (Objects.isNull(workflowDefinition)) {
            throw new ServiceException("查询流程定义失败:{}" + workflowDefinitionEnum);
        }

        String checkSql = " select workflow_id,workflow_status from " + workflowDefinition.getBusinessTable() + " where id = ? ";
        WorkflowEntity workflowEntity = this.jdbcTemplate.find(checkSql, WorkflowEntity.class, businessId);
        if (Objects.isNull(workflowEntity)) {
            throw new ServiceException("查询业务单据失败:" + workflowDefinitionEnum + "==" + businessId);
        }

        //已存在流程,如果是已驳回的,则重置流程(相当于重新启动),否则抛出异常
        if (Objects.nonNull(workflowEntity.getWorkflowId())) {
            if (Objects.equals(workflowEntity.getWorkflowStatus(), WorkflowStatusEnum.FAIL.getCode())) {
                this.reset(workflowEntity.getWorkflowId());
                return workflowEntity.getWorkflowId();
            }
            throw new ServiceException("已经发起过流程");
        }

        List<WorkflowDefinitionTask> definitionTaskList = workflowDefinitionTaskService.listByDefinitionEnum(workflowDefinitionEnum);
        if (CollectionUtils.isEmpty(definitionTaskList)) {
            throw new ServiceException("查询流程定义任务失败:{}" + workflowDefinitionEnum);
        }

        LambdaQueryWrapper<Workflow> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Workflow::getBusinessId, businessId);
        queryWrapper.eq(Workflow::getDefinitionCode, workflowDefinitionEnum);

        //创建流程实例
        Workflow workflow = this.getOne(queryWrapper);

        Date now = new Date();

        if (Objects.isNull(workflow)) {
            workflow = new Workflow();
            workflow.setDefinitionCode(workflowDefinition.getDefinitionCode());
            workflow.setDefinitionName(workflowDefinition.getDefinitionName());
            workflow.setDefinitionType(workflowDefinition.getDefinitionType());
            workflow.setBusinessId(businessId);
            workflow.setBusinessCode(workflowDefinition.getDefinitionCode());
            workflow.setBusinessTable(workflowDefinition.getBusinessTable());
            workflow.setStartTime(now);
            workflow.setWorkflowStatus(WorkflowStatusEnum.WAITING.getCode());
            this.save(workflow);
        }
        workflow.setWorkflowStatus(WorkflowStatusEnum.WAITING.getCode());

        //创建流程任务实例
        List<WorkflowTask> taskList = Lists.newArrayList();

        WorkflowTask first = null;
        WorkflowTask firstTask = null;//第一个需要审核的节点


        LoginUser loginUser = SecurityUtils.getLoginUserTry();
        Long userId = null;
        String userName = null;
        if (Objects.nonNull(loginUser)) {
            userId = loginUser.getUserId();
            userName = loginUser.getUsername();
        }

        for (WorkflowDefinitionTask workflowDefinitionTask : definitionTaskList) {
            WorkflowTask workflowTask = definitionTask2Task(workflowDefinitionTask);
            workflowTask.setWorkflowId(workflow.getId());
            workflowTask.setBusinessId(businessId);
            workflowTask.setBusinessCode(workflowDefinitionEnum.toString());
            workflowTask.setFlag(WorkflowConstants.TASK_FLAG_1);
            if (Objects.equals(workflowDefinitionTask.getTaskType(), WorkflowConstants.TASK_TYPE_0)) {
                workflowTask.setUserId(userId);
                workflowTask.setUserName(userName);
                workflowTask.setTaskStatus(WorkflowConstants.TASK_STATUS_1);
                workflowTask.setProcessTime(now);
                if (first == null) {
                    first = workflowTask;
                }
            } else {
                workflowTask.setTaskStatus(WorkflowConstants.TASK_STATUS_0);
                if (firstTask == null) {
                    firstTask = workflowTask;
                    firstTask.setFlag(WorkflowConstants.TASK_FLAG_0);
                }
            }
            workflowTask.setTaskFormStatus(WorkflowConstants.TASK_FORM_STATUS_0);
            taskList.add(workflowTask);
        }

        this.workflowTaskService.insertBatchFast(taskList);

        //串行设置流程实例的当前任务实例信息, 并行流程没有当前任务的概念
        if (Objects.equals(workflow.getDefinitionType(), WorkflowConstants.DEFINITION_TYPE_0)) {
            LambdaUpdateWrapper<Workflow> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Workflow::getId, workflow.getId());
            updateWrapper.set(Workflow::getTaskId, firstTask.getId());
            updateWrapper.set(Workflow::getTaskName, firstTask.getTaskName());
            updateWrapper.set(Workflow::getRoleCode, firstTask.getRoleCode());
            this.update(updateWrapper);
        }

        WorkflowLog workflowLog;
        if (Objects.isNull(first)) {
            workflowLog = new WorkflowLog();
            workflowLog.setTaskName("流程启动");
            workflowLog.setTaskType(WorkflowConstants.TASK_TYPE_0);
            workflowLog.setUserId(userId);
            workflowLog.setUserName(userName);
        } else {
            workflowLog = task2Log(first);
        }
        this.workflowLogService.save(workflowLog);

        workflow.setLastApproveTime(now);
        this.updateBusiness(workflow);

        return workflow.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long approve(WorkflowApproveRequest request) {
        Workflow workflow = this.getById(request.getWorkflowId());
        if (Objects.isNull(workflow)) {
            throw new ServiceException("查询流程实例失败");
        }

        //并行流程走并行逻辑
        if (Objects.equals(workflow.getDefinitionType(), WorkflowConstants.DEFINITION_TYPE_1)) {
            parallelApprove(workflow, request);
            return null;
        }

        if (Objects.isNull(workflow.getTaskId())) {
            throw new ServiceException("流程已经结束");
        }

        if (!roleService.checkRole(SecurityUtils.getUserId(), RoleEnum.WORKFLOW.getRoleKey(), workflow.getRoleCode())) {
            throw new ServiceException("权限不足");
        }

        WorkflowTask workflowTask = workflowTaskService.getById(workflow.getTaskId());

        if (Objects.isNull(workflowTask)) {
            throw new ServiceException("查询流程任务实例失败");
        }

        Date now = new Date();

        workflowTask.setTaskStatus(WorkflowConstants.TASK_STATUS_1);
        workflowTask.setUserId(SecurityUtils.getUserId());
        workflowTask.setUserName(SecurityUtils.getUsername());
        workflowTask.setTaskInfo(request.getTaskInfo());
        workflowTask.setFlag(WorkflowConstants.TASK_FLAG_1);
        workflowTask.setProcessTime(now);
        this.workflowTaskService.updateById(workflowTask);

        WorkflowLog workflowLog = this.task2Log(workflowTask);
        this.workflowLogService.save(workflowLog);

        addAttachments(request.getAttachments(), workflowTask.getId(), workflowLog.getId());

        WorkflowTask nextTask = workflowTaskService.nextTask(workflowTask);

        //没有后续节点,流程结束
        if (Objects.isNull(nextTask)) {
            workflow.setTaskId(null);
            workflow.setTaskName(null);
            workflow.setRoleCode(null);
            workflow.setEndTime(now);
            workflow.setWorkflowStatus(WorkflowStatusEnum.PASS.getCode());
        } else {
            //先把下一个任务置为当前节点
            nextTask.setFlag(WorkflowConstants.TASK_FLAG_0);
            this.workflowTaskService.updateById(nextTask);

            workflow.setTaskId(nextTask.getId());
            workflow.setTaskName(nextTask.getTaskName());
            workflow.setRoleCode(nextTask.getRoleCode());
            if (Objects.equals(workflowTask.getTaskType(), WorkflowConstants.TASK_TYPE_2)) {
                workflow.setWorkflowStatus(WorkflowStatusEnum.PASS.getCode());
                workflow.setEndTime(now);
                workflow.setWorkflowRemark(workflowTask.getTaskInfo());
            } else if (!Objects.equals(workflow.getWorkflowStatus(), WorkflowStatusEnum.PASS)) {
                workflow.setWorkflowStatus(WorkflowStatusEnum.APPROVING.getCode());
            }
        }

        LambdaUpdateWrapper<Workflow> updateWorkflowWrapper = new LambdaUpdateWrapper<>();
        updateWorkflowWrapper.eq(Workflow::getId, workflow.getId());
        updateWorkflowWrapper.set(Workflow::getTaskId, workflow.getTaskId());
        updateWorkflowWrapper.set(Workflow::getTaskName, workflow.getTaskName());
        updateWorkflowWrapper.set(Workflow::getRoleCode, workflow.getRoleCode());
        updateWorkflowWrapper.set(Workflow::getStartTime, workflow.getStartTime());
        updateWorkflowWrapper.set(Workflow::getEndTime, workflow.getEndTime());
        updateWorkflowWrapper.set(Workflow::getWorkflowStatus, workflow.getWorkflowStatus());
        this.update(updateWorkflowWrapper);

        workflow.setLastApproveTime(now);
        this.updateBusiness(workflow);

        return workflow.getTaskId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long reject(WorkflowRejectRequest request) {
        Workflow workflow = this.getById(request.getWorkflowId());
        if (Objects.isNull(workflow)) {
            throw new ServiceException("查询流程实例失败");
        }

        //并行流程走并行逻辑
        if (Objects.equals(workflow.getDefinitionType(), WorkflowConstants.DEFINITION_TYPE_1)) {
            parallelReject(workflow, request);
            return null;
        }

        if (Objects.isNull(workflow.getTaskId())) {
            throw new ServiceException("流程已经结束");
        }

        if (!roleService.checkRole(SecurityUtils.getUserId(), RoleEnum.WORKFLOW.getRoleKey(), workflow.getRoleCode())) {
            throw new ServiceException("权限不足");
        }

        WorkflowTask workflowTask = workflowTaskService.getById(workflow.getTaskId());

        if (Objects.isNull(workflowTask)) {
            throw new ServiceException("查询流程任务实例失败");
        }

        if (!Objects.equals(workflowTask.getTaskStatus(), WorkflowConstants.TASK_STATUS_0)) {
            throw new ServiceException("当前任务已经审核完成");
        }

        Date now = new Date();

        workflowTask.setTaskStatus(WorkflowConstants.TASK_STATUS_2);
        workflowTask.setUserId(SecurityUtils.getUserId());
        workflowTask.setUserName(SecurityUtils.getUsername());
        workflowTask.setTaskInfo(request.getTaskInfo());
        workflowTask.setFlag(WorkflowConstants.TASK_FLAG_1);
        workflowTask.setProcessTime(now);
        this.workflowTaskService.updateById(workflowTask);

        WorkflowLog workflowLog = this.task2Log(workflowTask);
        this.workflowLogService.save(workflowLog);

        addAttachments(request.getAttachments(), workflowTask.getId(), workflowLog.getId());

        WorkflowTask prevTask = workflowTaskService.prevTask(workflowTask);

        //当前节点是主节点,没有前置节点,前置节点是启动节点,满足这3个条件任意一条,则流程整个驳回
        if (Objects.equals(workflowTask.getTaskType(), WorkflowConstants.TASK_TYPE_2) || Objects.isNull(prevTask) || Objects.equals(prevTask.getTaskType(), WorkflowConstants.TASK_TYPE_0)) {
            workflow.setTaskId(null);
            workflow.setTaskName(null);
            workflow.setRoleCode(null);
            workflow.setEndTime(now);
            workflow.setWorkflowStatus(WorkflowStatusEnum.FAIL.getCode());
        } else {
            //先把上一个任务置为当前节点
            prevTask.setFlag(WorkflowConstants.TASK_FLAG_0);
            prevTask.setTaskStatus(WorkflowConstants.TASK_STATUS_0);
            this.workflowTaskService.updateById(prevTask);

            workflow.setTaskId(prevTask.getId());
            workflow.setTaskName(prevTask.getTaskName());
            workflow.setRoleCode(prevTask.getRoleCode());
            if (Objects.equals(workflowTask.getTaskType(), WorkflowConstants.TASK_TYPE_2)) {
                workflow.setWorkflowStatus(WorkflowStatusEnum.FAIL.getCode());
                workflow.setEndTime(now);
                workflow.setWorkflowRemark(workflowTask.getTaskInfo());
            } else if (!Objects.equals(workflow.getWorkflowStatus(), WorkflowStatusEnum.PASS.getCode())) {
                workflow.setWorkflowStatus(WorkflowStatusEnum.APPROVING.getCode());
            }
        }

        LambdaUpdateWrapper<Workflow> updateWorkflowWrapper = new LambdaUpdateWrapper<>();
        updateWorkflowWrapper.eq(Workflow::getId, workflow.getId());
        updateWorkflowWrapper.set(Workflow::getTaskId, workflow.getTaskId());
        updateWorkflowWrapper.set(Workflow::getTaskName, workflow.getTaskName());
        updateWorkflowWrapper.set(Workflow::getRoleCode, workflow.getRoleCode());
        updateWorkflowWrapper.set(Workflow::getStartTime, workflow.getStartTime());
        updateWorkflowWrapper.set(Workflow::getEndTime, workflow.getEndTime());
        updateWorkflowWrapper.set(Workflow::getWorkflowStatus, workflow.getWorkflowStatus());
        this.update(updateWorkflowWrapper);

        workflow.setLastApproveTime(now);
        this.updateBusiness(workflow);
        return workflow.getTaskId();
    }

    /**
     * 并行通过
     *
     * @param workflow
     * @return
     */
    private void parallelApprove(Workflow workflow, WorkflowApproveRequest request) {

        if (Objects.isNull(request.getTaskId())) {
            throw new ServiceException("请选择审批任务");
        }

        WorkflowTask workflowTask = this.workflowTaskService.getById(request.getTaskId());

        if (Objects.isNull(workflowTask)) {
            throw new ServiceException("查询流程任务实例失败");
        }

        if (!roleService.checkRole(SecurityUtils.getUserId(), RoleEnum.WORKFLOW.getRoleKey(), workflowTask.getRoleCode())) {
            throw new ServiceException("权限不足");
        }

        if (!Objects.equals(workflowTask.getTaskStatus(), WorkflowConstants.TASK_STATUS_0)) {
            throw new ServiceException("当前任务已经审核完成");
        }

        Date now = new Date();

        workflowTask.setTaskStatus(WorkflowConstants.TASK_STATUS_1);
        workflowTask.setUserId(SecurityUtils.getUserId());
        workflowTask.setUserName(SecurityUtils.getUsername());
        workflowTask.setTaskInfo(request.getTaskInfo());
        workflowTask.setFlag(WorkflowConstants.TASK_FLAG_1);
        workflowTask.setProcessTime(now);
        this.workflowTaskService.updateById(workflowTask);

        WorkflowLog workflowLog = this.task2Log(workflowTask);
        this.workflowLogService.save(workflowLog);

        addAttachments(request.getAttachments(), workflowTask.getId(), workflowLog.getId());

        workflow.setLastApproveTime(now);

        if (Objects.equals(workflowTask.getTaskType(), WorkflowConstants.TASK_TYPE_2)) {
            workflow.setWorkflowStatus(WorkflowStatusEnum.PASS.getCode());
            workflow.setEndTime(now);
            workflow.setWorkflowRemark(workflowTask.getTaskInfo());
            this.updateById(workflow);
            this.updateBusiness(workflow);
            return;
        }

        List<WorkflowTask> workflowTaskList = this.workflowTaskService.listByWorkflowId(workflow.getId());
        if (CollectionUtils.isEmpty(workflowTaskList)) {
            throw new ServiceException("查询流程任务实例失败");
        }

        boolean flag = true;
        for (WorkflowTask task : workflowTaskList) {
            //只要有一个不是审批通过的,整个流程就没有结束
            if (!Objects.equals(task.getTaskStatus(), WorkflowConstants.TASK_STATUS_1)) {
                flag = false;
            }
        }
        if (flag) {
            workflow.setEndTime(now);
            workflow.setWorkflowStatus(WorkflowStatusEnum.PASS.getCode());
            workflow.setWorkflowRemark(workflowTask.getTaskInfo());
        } else {
            workflow.setWorkflowStatus(WorkflowStatusEnum.WAITING.getCode());
        }
        this.updateById(workflow);

        this.updateBusiness(workflow);
    }

    /**
     * 并行驳回
     *
     * @param workflow
     * @return
     */
    private void parallelReject(Workflow workflow, WorkflowRejectRequest request) {
        if (Objects.isNull(request.getTaskId())) {
            throw new ServiceException("请选择审批任务");
        }

        WorkflowTask workflowTask = this.workflowTaskService.getById(request.getTaskId());

        if (Objects.isNull(workflowTask)) {
            throw new ServiceException("查询流程任务实例失败");
        }

        if (!roleService.checkRole(SecurityUtils.getUserId(), RoleEnum.WORKFLOW.getRoleKey(), workflowTask.getRoleCode())) {
            throw new ServiceException("权限不足");
        }

        if (!Objects.equals(workflowTask.getTaskStatus(), WorkflowConstants.TASK_STATUS_0)) {
            throw new ServiceException("当前任务已经审核完成");
        }

        Date now = new Date();

        workflowTask.setTaskStatus(WorkflowConstants.TASK_STATUS_2);
        workflowTask.setUserId(SecurityUtils.getUserId());
        workflowTask.setUserName(SecurityUtils.getUsername());
        workflowTask.setTaskInfo(request.getTaskInfo());
        workflowTask.setFlag(WorkflowConstants.TASK_FLAG_1);
        workflowTask.setProcessTime(now);
        this.workflowTaskService.updateById(workflowTask);

        WorkflowLog workflowLog = this.task2Log(workflowTask);
        this.workflowLogService.save(workflowLog);

        addAttachments(request.getAttachments(), workflowTask.getId(), workflowLog.getId());

        workflow.setLastApproveTime(now);
        if (Objects.equals(workflowTask.getTaskType(), WorkflowConstants.TASK_TYPE_2)) {
            workflow.setWorkflowStatus(WorkflowStatusEnum.FAIL.getCode());
            workflow.setEndTime(now);
            workflow.setWorkflowRemark(workflowTask.getTaskInfo());
        } else {
            workflow.setWorkflowStatus(WorkflowStatusEnum.WAITING.getCode());
        }
        this.updateById(workflow);

        this.updateBusiness(workflow);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long reset(Long workflowId) {
        //只有管理员可以重置流程
        if (!roleService.checkRole(SecurityUtils.getUserId(), RoleEnum.WORKFLOW)) {
            throw new ServiceException("权限不足");
        }

        Workflow workflow = this.getById(workflowId);

        List<WorkflowTask> taskList = this.workflowTaskService.listByWorkflowId(workflowId);
        if (CollectionUtils.isEmpty(taskList)) {
            throw new ServiceException("流程实例为空,数据异常");
        }

        Date now = new Date();

        WorkflowTask firstTask = workflowTaskService.firstTask(workflowId, WorkflowConstants.TASK_TYPE_1, WorkflowConstants.TASK_TYPE_2);

        StringBuilder updateTaskSql = new StringBuilder();
        updateTaskSql.append(" update t_workflow_task ");
        updateTaskSql.append(" set user_id = ?, ");
        updateTaskSql.append("     user_name = ?, ");
        updateTaskSql.append("     task_status = ?, ");
        updateTaskSql.append("     task_form_status = ?, ");
        updateTaskSql.append("     task_info = ?, ");
        updateTaskSql.append("     process_time = ?, ");
        updateTaskSql.append("     flag = ? ");
        updateTaskSql.append(" where id = ? ");

        List<Object[]> params = Lists.newArrayList();
        taskList.forEach(temp -> {
            Object[] param = new Object[8];

            param[7] = temp.getId();
            if (Objects.equals(temp.getId(), firstTask.getId())) {
                param[6] = WorkflowConstants.TASK_FLAG_0;
            } else {
                param[6] = WorkflowConstants.TASK_FLAG_1;
            }

            if (Objects.equals(temp.getTaskType(), WorkflowConstants.TASK_TYPE_0)) {//启动任务
                param[0] = temp.getUserId();
                param[1] = temp.getUserName();
                param[2] = temp.getTaskStatus();
                param[3] = temp.getTaskFormStatus();
                param[4] = temp.getTaskInfo();
                param[5] = DateUtil.formatDateTime(now);
            } else {//其他需要审核的任务
                param[0] = null;
                param[1] = null;
                param[2] = WorkflowConstants.TASK_STATUS_0;
                param[3] = null;
                param[4] = null;
                param[5] = null;
            }
            params.add(param);
        });
        log.debug("初始化流程==" + updateTaskSql + "\n" + JSON.toJSONString(params));
        this.jdbcTemplate.batchUpdate(updateTaskSql.toString(), params);

        if (Objects.equals(workflow.getDefinitionType(), WorkflowConstants.DEFINITION_TYPE_0)) {
            //串行流程种当前节点是主节点,没有前置节点,前置节点是启动节点,满足这3个条件任意一条,则流程整个驳回
            workflow.setTaskId(firstTask.getId());
            workflow.setTaskName(firstTask.getTaskName());
            workflow.setRoleCode(firstTask.getRoleCode());
        } else {
            //并行流程没有当前审批节点的概念
            workflow.setTaskId(null);
            workflow.setTaskName(null);
            workflow.setRoleCode(null);
        }

        workflow.setStartTime(new Date());
        workflow.setEndTime(null);
        workflow.setWorkflowStatus(WorkflowStatusEnum.WAITING.getCode());
        workflow.setWorkflowRemark("");
        LambdaUpdateWrapper<Workflow> updateWorkflowWrapper = new LambdaUpdateWrapper<>();
        updateWorkflowWrapper.eq(Workflow::getId, workflow.getId());
        updateWorkflowWrapper.set(Workflow::getTaskId, workflow.getTaskId());
        updateWorkflowWrapper.set(Workflow::getTaskName, workflow.getTaskName());
        updateWorkflowWrapper.set(Workflow::getRoleCode, workflow.getRoleCode());
        updateWorkflowWrapper.set(Workflow::getStartTime, workflow.getStartTime());
        updateWorkflowWrapper.set(Workflow::getEndTime, workflow.getEndTime());
        updateWorkflowWrapper.set(Workflow::getWorkflowStatus, workflow.getWorkflowStatus());
        this.update(updateWorkflowWrapper);

        //删除历史审批记录
        LambdaQueryWrapper<WorkflowLog> deleteWrapper = new LambdaQueryWrapper<>();
        deleteWrapper.eq(WorkflowLog::getWorkflowId, workflow.getId());
        this.workflowLogService.remove(deleteWrapper);

        //修改业务表信息
        updateBusiness(workflow);
        return workflow.getId();
    }

    /**
     * 修改业务表信息
     *
     * @param workflow
     */
    private void updateBusiness(Workflow workflow) {
        StringBuilder sb = new StringBuilder();
        List<Object> params = Lists.newArrayList();

        sb.append(" update ").append(workflow.getBusinessTable());
        sb.append(" set workflow_id = ?, ");
        params.add(workflow.getId());

        if (Objects.nonNull(workflow.getTaskId())) {
            sb.append(" workflow_task_id = ?, ");
            params.add(workflow.getTaskId());
        }
        if (Objects.nonNull(workflow.getTaskName())) {
            sb.append(" workflow_task_name = ?, ");
            params.add(workflow.getTaskName());
        }
        if (Objects.nonNull(workflow.getStartTime())) {
            sb.append(" workflow_start_time = ?, ");
            params.add(workflow.getStartTime());
        }
        if (Objects.nonNull(workflow.getEndTime())) {
            sb.append(" workflow_end_time = ?, ");
            params.add(workflow.getEndTime());
        }
        if (Objects.nonNull(workflow.getLastApproveTime())) {
            sb.append(" last_approve_time = ?, ");
            params.add(workflow.getLastApproveTime());
        }
        if (Objects.nonNull(workflow.getWorkflowRemark())) {
            sb.append(" workflow_remark = ?, ");
            params.add(workflow.getWorkflowRemark());
        }
        sb.append(" workflow_status = ? ");
        params.add(workflow.getWorkflowStatus());
        sb.append(" where id = ? ");
        params.add(workflow.getBusinessId());

        log.debug("初始化业务表单" + sb);
        log.debug(JSON.toJSONString(params));

        this.jdbcTemplate.update(sb.toString(), params.toArray());

        this.updateBusinessSearch(workflow);
    }

    /**
     * 修改业务父表信息
     *
     * @param workflow
     */
    private void updateBusinessSearch(Workflow workflow) {
        StringBuilder sb = new StringBuilder();
        List<Object> params = Lists.newArrayList();

        sb.append(" update oa_search ");
        sb.append(" set workflow_id = ?, ");
        params.add(workflow.getId());

        if (Objects.nonNull(workflow.getTaskId())) {
            sb.append(" workflow_task_id = ?, ");
            params.add(workflow.getTaskId());
        }
        if (Objects.nonNull(workflow.getTaskName())) {
            sb.append(" workflow_task_name = ?, ");
            params.add(workflow.getTaskName());
        }
        if (Objects.nonNull(workflow.getStartTime())) {
            sb.append(" workflow_start_time = ?, ");
            params.add(workflow.getStartTime());
        }
        if (Objects.nonNull(workflow.getEndTime())) {
            sb.append(" workflow_end_time = ?, ");
            params.add(workflow.getEndTime());
        }
        if (Objects.nonNull(workflow.getLastApproveTime())) {
            sb.append(" last_approve_time = ?, ");
            params.add(workflow.getLastApproveTime());
        }
        if (Objects.nonNull(workflow.getWorkflowRemark())) {
            sb.append(" workflow_remark = ?, ");
            params.add(workflow.getWorkflowRemark());
        }
        sb.append(" workflow_status = ? ");
        params.add(workflow.getWorkflowStatus());

        sb.append(" where oa_id = ? ");
        params.add(workflow.getBusinessId());
        sb.append(" and definition_code = ? ");
        params.add(workflow.getDefinitionCode());

        this.jdbcTemplate.update(sb.toString(), params.toArray());
    }

    private WorkflowTask definitionTask2Task(WorkflowDefinitionTask workflowDefinitionTask) {
        WorkflowTask workflowTask = new WorkflowTask();
        workflowTask.setDefinitionTaskId(workflowDefinitionTask.getId());
        workflowTask.setTaskCode(workflowDefinitionTask.getTaskCode());
        workflowTask.setTaskName(workflowDefinitionTask.getTaskName());
        workflowTask.setTaskType(workflowDefinitionTask.getTaskType());
        workflowTask.setTaskFormPath(workflowDefinitionTask.getTaskFormPath());
        workflowTask.setTaskFormName(workflowDefinitionTask.getTaskFormName());
        workflowTask.setFileFlag(workflowDefinitionTask.getFileFlag());
        workflowTask.setRoleCode(workflowDefinitionTask.getRoleCode());
        workflowTask.setFormDefault(workflowDefinitionTask.getFormDefault());
        workflowTask.setSortNum(workflowDefinitionTask.getSortNum());
        workflowTask.setTaskFormStatus(WorkflowConstants.TASK_FORM_STATUS_0);
        return workflowTask;
    }

    private WorkflowLog task2Log(WorkflowTask workflowTask) {
        WorkflowLog workflowLog = new WorkflowLog();
        workflowLog.setDefinitionTaskId(workflowTask.getDefinitionTaskId());
        workflowLog.setTaskId(workflowTask.getId());
        workflowLog.setWorkflowId(workflowTask.getWorkflowId());
        workflowLog.setBusinessId(workflowTask.getBusinessId());
        workflowLog.setBusinessCode(workflowTask.getBusinessCode());
        workflowLog.setTaskCode(workflowTask.getTaskCode());
        workflowLog.setTaskName(workflowTask.getTaskName());
        workflowLog.setTaskType(workflowTask.getTaskType());
        workflowLog.setRoleCode(workflowTask.getRoleCode());
        workflowLog.setUserId(workflowTask.getUserId());
        workflowLog.setUserName(workflowTask.getUserName());
        workflowLog.setTaskStatus(workflowTask.getTaskStatus());
        workflowLog.setTaskFormStatus(workflowTask.getTaskFormStatus());
        workflowLog.setTaskInfo(workflowTask.getTaskInfo());
        workflowLog.setFlag(workflowTask.getFlag());
        return workflowLog;
    }

    private void addAttachments(MultipartFile[] attachments, Long taskId, Long logId) {
        if (Objects.isNull(attachments) || attachments.length == 0) {
            return;
        }
        List<FileLink> fileLinkList = fileLinkService.link(attachments, FileBusinessType.WORKFLOW_TASK, taskId);

        fileLinkList.forEach(fileLink -> {
            fileLink.setId(null);
            fileLink.setBusinessId(logId);
            fileLink.setBusinessType(FileBusinessType.WORKFLOW_TASK_LOG.getCode());
        });
        this.fileLinkService.insertBatchFast(fileLinkList);
    }
}
